package cn.mw.cmdb.convert;

import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.PropDesc;
import cn.hutool.core.convert.Convert;
import cn.mw.cmdb.entity.ModelInfo;
import cn.mw.cmdb.entity.PropertyInfo;
import cn.mw.components.mongodb.anno.AutoId;
import cn.mw.components.mongodb.anno.CMDBProperty;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@Slf4j
public abstract class BasicServiceParamConverter<T> implements ServiceParamConvert<T>{
    public void convert(Map src, T dest) throws Exception{
        ServiceParamConvertContext serviceParamConvertContext = new ServiceParamConvertContext();
        BeanDesc desc = BeanUtil.getBeanDesc(dest.getClass());
        Iterator<PropDesc> ite = desc.getProps().iterator();
        while (ite.hasNext()) {
            PropDesc propDesc = ite.next();
            Field field = propDesc.getField();
            Annotation annotation = field.getAnnotation(CMDBProperty.class);
            Annotation autoId = field.getAnnotation(AutoId.class);
            if(null != annotation || null != autoId){
                CMDBProperty cmdbModelProperty = (CMDBProperty) annotation;
                Object value = null;
                String fieldName = propDesc.getFieldName();
                //处理模型内置属性
                if(null != cmdbModelProperty && ModelInfo.PropertyMap.equals(cmdbModelProperty.value())){
                    List propertiesList = (List)src.get(ModelInfo.PropertyMap);
                    if(null != propertiesList){
                        Map map = new HashMap<>();
                        for(Object property : propertiesList){
                            Map<String, Object> obj = (Map) property;
                            PropertyInfo propertyInfo = new PropertyInfo();
                            BeanUtil.fillBeanWithMap(obj ,propertyInfo ,false);
                            map.put(propertyInfo.getId() ,propertyInfo);
                        }
                        value = map;
                    }
                }else {
                    value = src.get(fieldName);
                }
                if(null != value){
                    Method method = desc.getSetter(fieldName);
                    try{
                        Object obj = Convert.convert(field.getType() ,value);
                        method.invoke(dest,obj);
                    }catch (Exception e){
                        log.warn("field {} {} convert value type {} ,error" ,fieldName ,field.getType().getName() ,value.getClass().getName() ,e);
                    }
                    serviceParamConvertContext.addConvertedFieldName(fieldName);
                }
            }
        }
        doConvert(src ,dest ,serviceParamConvertContext);
    }

    abstract void doConvert(Map src, T dest, ServiceParamConvertContext serviceParamConvertContext) throws Exception;
}
